#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#define NTHREADS 4 //Numero de threads que serao executadas ao mesmo tempo

double S; //Valor da acao ( Asset value )
double E; //preco de exercicio da opcao ( Exercise Price )
double r; // taxa de juros ( Interest rate )
double sigma; // volatilidade da acao ( Volatility )
double T; //Tempo de validade da acao ( Expirity time )
int M; //Numero de interacoes ( Number of trials )
double temp; //Variavel temporaria
pthread_t threadBS[NTHREADS];  // vetor de threads a ser utilizado
double *intervaloConfianca;
double *trials; //Vetor de iteracoes do metodo de Monte Carlo
double *soma;
double mean; //Media dos valores do vetor trials

double funcaoRandomica() //Funcao randomica.. encontrar uma melhor
{
    double nRandom;
    nRandom = (double)rand()/RAND_MAX;
    return nRandom;
}

void *standard_deviation(void* param){

    int size = M/NTHREADS;
//    printf("\ns%d ",size);
    if(0 == size)
        pthread_exit(0);

    int index = (int)param;
   // printf("i%d ", index);
     double sum_deviation=0.0;
    int i;
    int begin = index*size;
    int end = begin + size;
   // printf("b%lf e%lf \n", mean, trials[begin]);    
    for(i = begin; i < end; i++){
        intervaloConfianca[index] +=(trials[i]-mean)*(trials[i]-mean); //Formula do desvio padrao
    }
 //  printf("%lf ",intervaloConfianca[index]);
    pthread_exit(0);
}
    
void *calculaBS(void *param){

    double maxNumber; //Guarda o maior valor entre zero e temp-E
    int i, index = (int)param;
   int size = M/NTHREADS;
    
    int begin = index*size;
    int end = begin + size;
    // printf("b%lf e%lf \n", mean, trials[begin]);    
    for(i = begin; i < end; i++){
  
        //Calcula a primeira parte da formula de Black Scholes
        temp = (S*exp((r - (sigma*sigma)/2)*T + (sigma*sqrt(T)*funcaoRandomica())/M));

        maxNumber = temp - E; //Verifica se temp - E e' maior que zero
        if (maxNumber < 0){
            maxNumber = 0;
        }

        //Calcula a segunda parte da formula e atribui o valor ao vetor de Monte Carlo
        trials[i] = (exp((-1*r)*T) * maxNumber);
        soma[index] = soma[index] + trials[i];
    }
    pthread_exit(0);
}

int main (int argc, char *argv[]){

    int i;
    double somaTotal = 0.0; //Soma total dos valores de todas as trials
    long double StdDevTotal = 0.0;
  

   srand(time(NULL)); //Inicializa a funcao randomica


    scanf("%lf %lf %lf %lf %lf %i", &S, &E, &r, &sigma, &T, &M );

    //Apenas para facilitar
    //S = 100.0;
//    E = 110.0;
  //  r = 10.0;
//    sigma = 1.0;
  //  T = 1.0;
    //M = 10;

    printf("S %lf\nE %lf\nr %lf\nsigma %lf\nT %lf\nM %i\n", S,E,r,sigma,T,M);

    //Aloca espaco para os vetores globais
    trials = (double*) malloc(sizeof(double)*M);
    soma = (double*) malloc(sizeof(double)*M);
    intervaloConfianca = (double*) malloc(sizeof(double)*M);


    for (i = 0; i< NTHREADS ; i++){
                //Cria as threads do vetor com a funcao de calcular o Black Scholes
                pthread_create (&threadBS[i], NULL, calculaBS, (void *)i);
    }
    for (i = 0; i< NTHREADS ; i++){ //Espera todas as threads concluirem
                pthread_join (threadBS[i], NULL);
                somaTotal = somaTotal + soma[i];
    }

    printf("Soma: %lf ", somaTotal);
    mean = somaTotal / M; //Calcula a media dos valores do vetor trials
    printf("Mean: %lf ", mean);

     
    for (i = 0; i< NTHREADS ; i++){
                //Cria as threads para paralelizar a Satandard Deviation
                pthread_create (&threadBS[i], NULL, standard_deviation, (void *)i);
    }
    for (i = 0; i< NTHREADS ; i++){ //Espera todas as threads concluirem
                pthread_join (threadBS[i], NULL);
                StdDevTotal = StdDevTotal + intervaloConfianca[i];
//		printf(",%Lf, ",StdDevTotal);
    }

	

    // aplica a ultima parte da formula
    long double confidence_interval = 1.96*(sqrt(StdDevTotal/M)/sqrt(M));


    printf("Confidence interval (%Lf,%Lf)\n", mean -confidence_interval, mean + confidence_interval);//Imprime o intervalo de confianca
    free(intervaloConfianca);
    free(soma);
    free(trials);

     return 0;
}
